
<template>
  <div class="image-upload-v2">
    <div
      v-for="(item, index) in fileList"
      :key="item.url"
      class="image-wrapper"
    >
      <!-- <el-image
        :src="item[urlKey]"
        :alt="item[nameKey]"
      /> -->

      <img
        class="img"
        :src="item[urlKey]"
        :alt="item[nameKey]"
      >

      <div class="hover-layer">
        <slot
          name="hover-layer"
          :item="item"
          :index="index"
          :add="add"
          :remove="remove"
          :replace="replace"
        >
          <div
            class="hover-button"
            @click="showBigImage(item)"
          >
            <el-icon><ZoomIn /></el-icon>
          </div>
          <div
            class="hover-button"
            @click="remove(index)"
          >
            <el-icon><Close /></el-icon>
          </div>
          <div
            class="hover-button"
            @click="replace(index)"
          >
            <el-icon><Refresh /></el-icon>
          </div>
        </slot>
      </div>
    </div>

    <div
      v-if="fileList.length < limit"
      class="image-wrapper image-upload-controller"
      @click="add"
    >
      <el-icon><PictureFilled /></el-icon>
    </div>
  </div>

  <input
    ref="fileInputRef"
    style="display: none;"
    type="file"
    :accept="accept"
    @input="handleInput"
  >

  <el-image-viewer
    v-if="showViewer"
    :initial-index="0"
    :url-list="[dialogImageUrl]"
    teleported
    @close="showViewer = false"
  />
</template>

<script lang="ts" setup>
import { upload as uploadFile } from "@/utils/minio-upload";
import { ComputedRef } from "vue";

const props = withDefaults(defineProps<{
  modelValue: {url: string; name: string}[] | string;
  limit?: number;
  filePath?: string;
  accept?: string;
  nameKey?: string;
  urlKey?: string;
  valueType?: 'single_url' | 'url_dot_splitted' | 'array_object'; // 字符串形式 | 逗号分隔的字符串 TODO 未测试 | 对象数组 TODO 未测试
}>(), {
  nameKey: "name",
  urlKey: "url",
  limit: 1,
  filePath: "marketing-center/",
  accept: ".jpg, .jpeg, .png",
  valueType: 'single_url'
});

const emits = defineEmits([ "update:model-value", "change" ]);

const fileList: ComputedRef<{url: string; name: string}[] | string> = computed(() => {
  // TODO 数组类型还没有测试过
  if (props.valueType === 'array_object') {
    return props.modelValue.map((item) => ({
      ...item,
      url: item[props.urlKey],
      name: item[props.nameKey],
    }));
  } else if (props.valueType === 'url_dot_splitted') {
    return props.modelValue && props.modelValue.split(",").map(item => {
      return {
        url: item,
        name: item,
      }
    }) || []
  } else {
    return props.modelValue ? [
      {
        url: props.modelValue,
        name: props.modelValue,
      }
    ] : []
  }
});

const fileInputRef = ref();

const showFileExporlor = () => {
  fileInputRef.value.click()
}

const handleInput = () => {
  Promise.all([ ...fileInputRef.value.files ].map((file:File) => uploadFile(file, props.filePath))) 
    .then((results) => {
      handleAfterInput(results)
      emits("change", results.map(item => ({ name: item.name, url: item.url })))
    })
    .then(() => {
      if (fileInputRef.value) {
        fileInputRef.value.value = ""
      }
    })
}

let handleAfterInput = (results: {name: string; url: string}[]) => {
  console.log("after input", results)
}

const replace = (index: number) => {
  handleAfterInput = (results) => {
    let formattedObjectArray, formattedUrlArray, formattedString

    if (props.valueType === 'array_object') {
      formattedObjectArray = [ ...props.modelValue ]
    } else if (props.valueType === 'url_dot_splitted') {
      formattedUrlArray = props.modelValue.split(",");
    } else {
      formattedString = ""
    }

    for (let i = 0; i < results.length; i++) {
      const _file = results[i]

      if (props.valueType === 'array_object') {
        formattedObjectArray.splice(index, 1, {
          url: _file.url as string,
          name: _file.name  as string,
        })
      } else if (props.valueType === 'url_dot_splitted') {
        formattedUrlArray.splice(index, 1, _file.url)
      } else {
        formattedString = _file.url;
      }
    }

    if (props.valueType === 'array_object') {
      emits("update:model-value", [ ...formattedObjectArray ])
    } else if (props.valueType === 'url_dot_splitted') {
      emits("update:model-value",  formattedUrlArray.join(","))
    } else {
      emits("update:model-value", formattedString)
    }
  }


  showFileExporlor();
}

const add = () => {
  handleAfterInput = (results) => {
    let formattedObjectArray, formattedUrlArray, formattedString

    if (props.valueType === 'array_object') {
      formattedObjectArray = [ ...props.modelValue ]
    } else if (props.valueType === 'url_dot_splitted') {
      formattedUrlArray = props.modelValue.split(",");
    } else {
      formattedString = ""
    }

    for (let i = 0; i < results.length; i++) {
      const _file = results[i]

      if (props.valueType === 'array_object') {
        formattedObjectArray.push({
          url: _file.url as string,
          name: _file.name  as string,
        })
      } else if (props.valueType === 'url_dot_splitted') {
        formattedUrlArray.push(_file.url)
      } else {
        formattedString = _file.url;
      }
    }

    if (props.valueType === 'array_object') {
      emits("update:model-value", [ ...formattedObjectArray ])
    } else if (props.valueType === 'url_dot_splitted') {
      emits("update:model-value",  formattedUrlArray.join(","))
    } else {
      emits("update:model-value", formattedString)
    }
  }

  showFileExporlor();
}


const showViewer = ref(false);
const dialogImageUrl = ref("");
const showBigImage = ({ url }: {url: string}) => {
  showViewer.value = true
  dialogImageUrl.value = url
}

const remove = (index: number) => {
  const _modelValue = [ ...fileList.value ]
  _modelValue.splice(index, 1);

  if (props.valueType === 'array_object') {
    emits("update:model-value", _modelValue)
  } else if (props.valueType === 'url_dot_splitted') {
    emits("update:model-value", _modelValue.map(item => item.url).join(","))
  } else {
    emits("update:model-value", "");
  }

  emits("change", _modelValue.map(item => ({ 
    name: item.name, 
    url: item.url 
  })))
}

defineExpose({
  remove,
  replace,
  add,
})
</script>
<style lang="scss" scoped>
.image-upload-v2 {
  display: flex;
}

.image-upload-v2 + .image-upload-v2 {
  margin-left: 10px;
}

.image-wrapper {
  flex-shrink: 0;
  width: 50px;
  height: 50px;
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;

  .img {
    max-width: 50px;
    max-height: 50px;
  }
}

.image-wrapper:not(:last-child) {
  margin-right: 10px;
}

.image-wrapper:hover {
  .hover-layer {
    display: flex;
  }
}

.image-upload-controller {
  border: dashed 1px #999;
  cursor: pointer;
  box-sizing: border-box;
}

.image-upload-controller:hover {
  color: var(--el-color-primary);
  border: dashed 1px var(--el-color-primary);
}

.hover-layer {
  display: none;
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: rgba(255, 255, 255, 0.8);
  flex-direction: column;
  justify-content: center;
  align-items: center;

  .hover-button {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    width: 100%;
  }

  .hover-button:not(:last-child) {
    border-bottom: solid 1px #CCC;
  }
}
</style>
